package cn.bearspark.api.service.main.impl;

import cn.bearspark.api.service.main.ArticleService;
import cn.bearspark.api.vo.main.article.*;
import cn.bearspark.api.vo.main.category.CategorySimpleVO;
import cn.bearspark.api.vo.main.category.CategorySlimVO;
import cn.bearspark.api.vo.main.user.UserSlimVO;
import cn.bearspark.article.dto.article.*;
import cn.bearspark.article.rpc.ArticleRpc;
import cn.bearspark.collect.rpc.CollectRpc;
import cn.bearspark.common.constant.GlobalConstant;
import cn.bearspark.common.enumeration.*;
import cn.bearspark.common.util.ConvertBeanUtil;
import cn.bearspark.framework.web.starter.context.BSRequestContext;
import cn.bearspark.happening.dto.happening.LCFNumInfoDTO;
import cn.bearspark.happening.dto.happening.PublishHappeningReqDTO;
import cn.bearspark.happening.enumeration.happening.AdvanceReleaseEnum;
import cn.bearspark.happening.rpc.HappeningRpc;
import cn.bearspark.idgenerator.enumeration.IdCodeEnum;
import cn.bearspark.idgenerator.rpc.IdGeneratorRpc;
import cn.bearspark.like.rpc.LikeRpc;
import cn.bearspark.merit.rpc.AccMeritRpc;
import cn.bearspark.tag.rpc.TagRpc;
import cn.bearspark.user.rpc.UserBaseRpc;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author f
 */
@Service
public class ArticleServiceImpl implements ArticleService {

    @DubboReference(check = GlobalConstant.DUBBO_CHECK)
    private ArticleRpc articleRpc;
    @DubboReference(check = GlobalConstant.DUBBO_CHECK)
    private UserBaseRpc userBaseRpc;
    @DubboReference(check = GlobalConstant.DUBBO_CHECK)
    private LikeRpc likeRpc;
    @DubboReference(check = GlobalConstant.DUBBO_CHECK)
    private AccMeritRpc accMeritRpc;
    @DubboReference(check = GlobalConstant.DUBBO_CHECK)
    private CollectRpc collectRpc;
    @DubboReference(check = GlobalConstant.DUBBO_CHECK)
    private TagRpc tagRpc;
    @DubboReference(check = GlobalConstant.DUBBO_CHECK)
    private IdGeneratorRpc idGeneratorRpc;
    @DubboReference(check = GlobalConstant.DUBBO_CHECK)
    private HappeningRpc happeningRpc;

    @Override
    public void publish(PublishArticleVO publishArticleVO) {
        long userId = BSRequestContext.getUserId();

        // 生成专栏 id
        long articleId = idGeneratorRpc.generateId(IdCodeEnum.ARTICLE_ID);

        // 发布专栏的动态
        long happeningId = publishHappening(publishArticleVO, userId);

        // 发布专栏
        PublishArticleDTO publishArticleDTO = ConvertBeanUtil.convert(publishArticleVO, PublishArticleDTO.class);
        publishArticleDTO.setArticleId(articleId);
        publishArticleDTO.setHappeningId(happeningId);
        publishArticleDTO.setUserId(userId);
        articleRpc.publish(publishArticleDTO);
    }

    // 发布专栏的动态
    private long publishHappening(PublishArticleVO publishArticleVO, long userId) {
        PublishHappeningReqDTO publishHappeningReqDTO = new PublishHappeningReqDTO();
        publishHappeningReqDTO.setUserId(userId);
        publishHappeningReqDTO.setTitle(publishArticleVO.getTitle());
        publishHappeningReqDTO.setContent(publishArticleVO.getSummary());
        publishHappeningReqDTO.setTagId(publishArticleVO.getTagId());
        publishHappeningReqDTO.setVisibility(publishArticleVO.getVisibility());
        publishHappeningReqDTO.setCommentAble(publishArticleVO.getCommentAble());
        publishHappeningReqDTO.setAdvanceRelease(AdvanceReleaseEnum.NO.getCode());
        publishHappeningReqDTO.setPubTime(publishArticleVO.getPubTime());
        return happeningRpc.publish(publishHappeningReqDTO);
    }

    @Override
    public Article4ModifyVO get(Long articleId) {
        long userId = BSRequestContext.getUserId();

        Article4ModifyDTO article4ModifyDTO = articleRpc.get(articleId, userId);
        if (article4ModifyDTO == null) {
            return null;
        }

        Article4ModifyVO article4ModifyVO = ConvertBeanUtil.convert(article4ModifyDTO, Article4ModifyVO.class);
        Long tagId = article4ModifyDTO.getTagId();
        if (tagId != null) {
            article4ModifyVO.setTag(tagRpc.getContent(tagId));
        }
        article4ModifyVO.setCategoryInfoList(ConvertBeanUtil.convertList(
                article4ModifyDTO.getCategorySimpleDTOList(), CategorySimpleVO.class));
        return article4ModifyVO;
    }

    @Override
    public void modify(ModifyArticleVO modifyArticleVO) {
        long userId = BSRequestContext.getUserId();

        if (modifyArticleVO.getVisibility() == VisibilityEnum.INVISIBLE.getCode()) {
            // 不能将专栏修改为 不可见，直接返回
            return;
        }

        ModifyArticleDTO modifyArticleDTO = ConvertBeanUtil.convert(modifyArticleVO, ModifyArticleDTO.class);
        modifyArticleDTO.setUserId(userId);
        articleRpc.modify(modifyArticleDTO);
    }

    @Override
    public void delete(Long articleId) {
        long userId = BSRequestContext.getUserId();

        // 删除专栏，并获取专栏的动态 id，如果动态 id 不为 null，则需要删除专栏的动态
        Long happeningId = articleRpc.delete(articleId, userId);
        if (happeningId != null) {
            happeningRpc.delete(userId, happeningId);
        }
    }

    @Override
    public ArticleDetailVO detail(Long articleId) {
        long userId = BSRequestContext.getUserId();

        ArticleDetailDTO articleDetailDTO = articleRpc.detail(articleId, userId);
        if (articleDetailDTO == null) {
            return null;
        }

        ArticleDetailVO articleDetailVO = ConvertBeanUtil.convert(articleDetailDTO, ArticleDetailVO.class);
        Long tagId = articleDetailDTO.getTagId();
        if (tagId != null) {
            articleDetailVO.setTag(tagRpc.getContent(tagId));
        }
        articleDetailVO.setCategoryInfoList(ConvertBeanUtil.convertList(
                articleDetailDTO.getCategorySlimDTOList(), CategorySlimVO.class));
        articleDetailVO.setPublisherInfo(ConvertBeanUtil.convert(
                userBaseRpc.getSlimInfo(articleDetailDTO.getPublisherId()), UserSlimVO.class));

        // 查询专栏的 点赞量、转发量、收藏量 信息
        long happeningId = articleDetailDTO.getHappeningId();
        LCFNumInfoDTO lcfNumInfoDTO = happeningRpc.getLCFNumInfo(happeningId);
        articleDetailVO.setLikeNumInfo(lcfNumInfoDTO.getLikeNumInfo());
        articleDetailVO.setCommentNumInfo(lcfNumInfoDTO.getCommentNumInfo());
        articleDetailVO.setForwardNumInfo(lcfNumInfoDTO.getForwardNumInfo());

        // 查询该用户是否 已点赞、积功德、已收藏 这个专栏
        articleDetailVO.setLiked(likeRpc.isHappeningLiked(happeningId, userId) ?
                LikedEnum.LIKED.getCode() :
                LikedEnum.UNLIKED.getCode());
        articleDetailVO.setMerited(accMeritRpc.isMerited(userId, ModuleEnum.ARTICLE.getCode(), articleId) ?
                MeritedEnum.MERITED.getCode() :
                MeritedEnum.UNMERITED.getCode());
        articleDetailVO.setCollected(collectRpc.isCollected(userId, ModuleEnum.ARTICLE.getCode(), articleId) ?
                CollectedEnum.COLLECTED.getCode() :
                CollectedEnum.UNCOLLECTED.getCode());

        return articleDetailVO;
    }

    @Override
    public List<ArticleSimpleVO> page(Integer pageNum, Integer pageSize, Long categoryId, Long listedUserId) {
        long userId = BSRequestContext.getUserId();

        List<ArticleSimpleDTO> articleSimpleDTOList =
                articleRpc.page(pageNum, pageSize, categoryId, userId, listedUserId);
        if (articleSimpleDTOList.isEmpty()) {
            return List.of();
        }

        // key：动态 id，value：专栏的简单数据对象
        Map<Long, ArticleSimpleVO> articleSimpleVOMap = new HashMap<>(articleSimpleDTOList.size());
        List<ArticleSimpleVO> articleSimpleVOList = articleSimpleDTOList.stream().map(articleSimpleDTO -> {
            ArticleSimpleVO articleSimpleVO = ConvertBeanUtil.convert(articleSimpleDTO, ArticleSimpleVO.class);
            articleSimpleVOMap.put(articleSimpleDTO.getHappeningId(), articleSimpleVO);
            return articleSimpleVO;
        }).toList();
        List<Long> happeningIdList = articleSimpleDTOList.stream().map(ArticleSimpleDTO::getHappeningId).toList();
        Map<Long, LCFNumInfoDTO> lcfNumInfoMap = happeningRpc.mapLCFNumInfo(happeningIdList);
        articleSimpleVOMap.forEach((happeningId, articleSimpleVO) -> {
            LCFNumInfoDTO lcfNumInfoDTO = lcfNumInfoMap.get(happeningId);
            articleSimpleVO.setLikeNumInfo(lcfNumInfoDTO.getLikeNumInfo());
            articleSimpleVO.setCommentNumInfo(lcfNumInfoDTO.getCommentNumInfo());
        });
        return articleSimpleVOList;
    }
}
